<?php
/************************************************************************
 Omnitrix - PHP Development Framework
 Copyright (C) 2012-2018 amonest(eastson@outlook.com)

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
************************************************************************/

class omnitrix_db_mysql
{
	protected $_link;
	protected $_params;

	public function __destruct()
	{
		if (null !== $this->_link) {
			$this->disconnect();
			$this->_link = null;
		}
	}

	public function connect($params)
	{
		$this->_params = $params;

		if (empty($this->_params['host']) ||
			empty($this->_params['username']) ||
			empty($this->_params['database'])) {
			throw new Exception('Invalid Mysql information provided');
		}

		$this->_link = @mysql_connect($this->_params['host'] . (isset($this->_params['port']) ? ':' . $this->_params['port'] : ''),
				$this->_params['username'], $this->_params['password']);
		if (!$this->_link) {
			throw new Exception('Mysql Server connect fail');
		}

		if (!mysql_select_db($this->_params['database'], $this->_link)) {
			throw new Exception($this, 'Mysql Server can not connect database');
		}

		if (isset($this->_params['charset'])) {
			$this->query("SET NAMES ?", str_replace('-', '', $this->_params['charset']));
		}

		if (version_compare(mysql_get_server_info($this->_link), '5.0.2', '>=')) {
			$this->query("SET SESSION SQL_MODE=''");
		}
	}

	public function disconnect()
	{
		@mysql_close($this->_link);
	}

	public function query($sql, $params = null)
	{
		if (isset($this->_params['prefix'])) {
			$sql = preg_replace('/#(.*)#/', $this->_params['prefix'] . '$1', $sql);
		}

		if (null !== $params) {
			if (!is_array($params)) {
				$params = array($params);
			}

			$sql = $this->_bind_params($sql, $params);
		}

		$sql = trim($sql);

		if (!$result =  mysql_query($sql, $this->_link)) {
			throw new Exception("SQL query failed: $sql");
		}

		return $result;
	}

	protected function _bind_params($sql, $params)
	{
		$sqlSplit = preg_split('/(\?|\:[a-zA-Z0-9_]+)/',
				$sql, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);

		$i = 0;

		foreach ($sqlSplit as $key => $val) {
			if ($val == '?') {
				if (isset($params[$i])) {
					$value = $params[$i];
				} else {
					$value = NULL;
				}

				$sqlSplit[$key] = $this->escape_value($value);
				$i++;
			} else if ($val[0] == ':') {
				$name = substr($val, 1);

				if (isset($params[$name])) {
					$value = $params[$name];
				} else {
					$value = NULL;
				}

				$sqlSplit[$key] = $this->escape_value($value);
			}
		}

		$sql = implode('', $sqlSplit);

		return $sql;
	}

	public function fetch_all($sql, $params = null, $mode = DB_FETCHMODE_DEFAULT)
	{
		$result = $this->query($sql, $params);

		if (mysql_num_rows($result) > 0) {
			$return = array();

			while ($row = $this->_fetch_result($result, $mode)) {
				$return[] = $row;
			}
		} else {
			$return = false;
		}

		mysql_free_result($result);

		return $return;
	}

	public function fetch_row($sql, $params = null, $mode = DB_FETCHMODE_DEFAULT)
	{
		$result = $this->query($sql, $params);

		if (mysql_num_rows($result) > 0) {
			$return = $this->_fetch_result($result, $mode);
		} else {
			$return = false;
		}

		mysql_free_result($result);

		return $return;
	}

	public function fetch_col($sql, $params = null)
	{
		$result = $this->query($sql, $params);

		if (mysql_num_rows($result) > 0) {
			$return = array();

			while ($row = $this->_fetch_result($result, DB_FETCHMODE_ORDERED)) {
				$return[] = $row[0];
			}
		} else {
			$return = false;
		}

		mysql_free_result($result);

		return $return;
	}

	public function fetch_pairs($sql, $params = null)
	{
		$result = $this->query($sql, $params);

		if (mysql_num_rows($result) > 0) {
			$return = array();

			while ($row = $this->_fetch_result($result, DB_FETCHMODE_ORDERED)) {
				if (count($row) > 1) {
					$return[$row[0]] = $row[1];
				} else {
					$return[] = $row[0];
				}
			}
		} else {
			$return = false;
		}

		mysql_free_result($result);

		return $return;
	}

	public function fetch_one($sql, $params = null)
	{
		$result = $this->query($sql, $params);

		if (mysql_num_rows($result) > 0) {
			$row = $this->_fetch_result($result, DB_FETCHMODE_ORDERED);
			$return = $row[0];
		} else {
			$return = false;
		}

		mysql_free_result($result);

		return $return;
	}

	protected function _fetch_result($result, $mode)
	{
		if ($mode == DB_FETCHMODE_ASSOC) {
			return mysql_fetch_assoc($result);
		} else if ($mode == DB_FETCHMODE_OBJECT) {
			return mysql_fetch_object($result);
		} else {
			return mysql_fetch_row($result);
		}
	}

	public function escape_identifier($s)
	{
		return '`' . $s . '`';
	}

	public function escape_value($s)
	{
		if (is_null($s)) {
			return 'NULL';
		} else if (is_int($s)) {
			return $s;
		} elseif (is_float($s)) {
			return sprintf('%F', $s);
		} elseif (is_bool($s)) {
			return $s ? 1 : 0;
		} elseif (is_array($s)) {
			if (empty($s)) {
				return 'NULL';
			} else {
				return $this->escape_value(serialize($s));
			}
		} else {
			return "'" . mysql_real_escape_string($s, $this->_link) . "'";
		}
	}

	public function last_inserted_id()
	{
		return mysql_insert_id($this->_link);
	}

	public function affected_rows()
	{
		return mysql_affected_rows($this->_link);
	}

	public function list_tables()
	{
		return $this->fetch_col('SHOW TABLES');
	}
}